package Monitor;

import Entity.User;
import GUI.MainFrame;
import Service.AddFriend;
import Service.ReceiveFile;
import Service.ReceiveMsg;
import Service.RequestFriStatus;
import Utils.MSG_TYPE;
import org.json.JSONObject;

import java.io.File;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.HashMap;

import static Client.Client.rootDir;

/**
 * The type Client thread.
 *
 * @author dzr
 * @version 1.0
 */
public class ClientThread extends Thread{
    private boolean exitStatus;
    private DatagramSocket socket;
    private final int uid;
    private final String username;
    private final int profileID;
    private String sex;
    private String birthday;
    private HashMap<Integer, User> friends_online;
    private DatagramPacket packet;
    private final File rootHistory;
    private final File rootImage;
    private final File fileRecv;
    private MainFrame mainFrame;

    /**
     * Gets socket.
     *
     * @return the socket
     */
    public DatagramSocket getSocket() {
        return socket;
    }

    /**
     * Sets exit status.
     *
     * @param exitStatus the exit status
     */
    public void setExitStatus(boolean exitStatus) {
        this.exitStatus = exitStatus;
    }

    /**
     * Sets socket.
     *
     * @param socket the socket
     */
    public void setSocket(DatagramSocket socket) {
        this.socket = socket;
    }

    /**
     * Sets online friends list.
     *
     * @param friends_online online friends list
     */
    public void setFriends_online(HashMap<Integer, User> friends_online) {
        HashMap<Integer, User> map = new HashMap<>();

        for (Integer uid:
             friends_online.keySet()) {
            JSONObject object = new JSONObject(friends_online.get(uid));
            map.put(uid, friends_online.get(uid));
        }
        this.friends_online = map;
    }

    /**
     * Instantiates a new Client thread.
     *
     * @param uid       the uid
     * @param username  the username
     * @param profileID the profile id
     * @param sex       the sex
     * @param birthday  the birthday
     * @param socket    the socket
     */
    public ClientThread(int uid, String username, int profileID, String sex, String birthday, DatagramSocket socket) {
        this.uid = uid;
        this.username = username;
        this.profileID = profileID;
        this.sex = sex;
        this.birthday = birthday;
        this.socket = socket;

        rootHistory = new File(rootDir.getPath() + File.separator + uid + File.separator + "chatHistory");
        if(! rootHistory.exists()){
            rootHistory.mkdirs();
        }

        rootImage = new File(rootHistory.getPath() + File.separator + "img");
        if (! rootImage.exists()){
            rootImage.mkdir();
        }

        fileRecv = new File(rootDir.getPath() + File.separator + uid + File.separator + "fileRecv");
        if(! fileRecv.exists()){
            fileRecv.mkdir();
        }
    }

    /**
     * Start the thread to listen for messages from the server.
     */
    @Override
    public void run() {
        while(!exitStatus){
            try {
                packet = new DatagramPacket(new byte[2048], 2048);
                socket.receive(packet);

                byte[] bytes = packet.getData();
                String data = new String(bytes, 0, packet.getLength());
                JSONObject retData = new JSONObject(data);

                MSG_TYPE msg_type = MSG_TYPE.valueOf(retData.getString("msg_type"));
                switch (msg_type){
                    case MSG_friend_new:{
                        AddFriend.result(retData);
                        break;
                    }
                    case MSG_friend_msg:{
                        ReceiveMsg.receiveMsg(retData);
                        break;
                    }
                    case MSG_friend_onlineNew:{
                        RequestFriStatus.addFriOnline(uid);
                        break;
                    }
                    case MSG_friend_outline:{
                        RequestFriStatus.delFriOutline(uid);
                        break;
                    }
                    case MSG_friend_file:{
                        ReceiveFile.receiveFile(retData);
                        break;
                    }
                    default:
                        break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Gets Directory of saving file.
     *
     * @return Directory of saving file
     */
    public File getFileRecv() {
        return fileRecv;
    }

    /**
     * Gets Directory of saving image.
     *
     * @return Directory of saving iamge
     */
    public File getRootImage() {
        return rootImage;
    }

    /**
     * Gets Directory of saving chatHistory.
     *
     * @return Directory of chatHistory
     */
    public File getRootHistory() {
        return rootHistory;
    }

    /**
     * Gets uid.
     *
     * @return the uid
     */
    public int getUid() {
        return uid;
    }

    /**
     * Gets profile id.
     *
     * @return the profile id
     */
    public int getProfileID() {
        return profileID;
    }

    /**
     * Gets username.
     *
     * @return the username
     */
    public String getUsername() {
        return username;
    }

    /**
     * Gets friends online.
     *
     * @return the friends online
     */
    public HashMap<Integer, User> getFriends_online() {
        return friends_online;
    }

    /**
     * Gets main frame.
     *
     * @return the main frame
     */
    public MainFrame getMainFrame() {
        return mainFrame;
    }

    /**
     * Sets main frame.
     *
     * @param mainFrame the main frame
     */
    public void setMainFrame(MainFrame mainFrame) {
        this.mainFrame = mainFrame;
    }

    /**
     * Gets sex.
     *
     * @return the sex
     */
    public String getSex() {
        return sex;
    }

    /**
     * Sets sex.
     *
     * @param sex the sex
     */
    public void setSex(String sex) {
        this.sex = sex;
    }

    /**
     * Gets birthday.
     *
     * @return the birthday
     */
    public String getBirthday() {
        return birthday;
    }

    /**
     * Sets birthday.
     *
     * @param birthday the birthday
     */
    public void setBirthday(String birthday) {
        this.birthday = birthday;
    }
}
